package com.agent.vpsserver.common.utils.date;

import com.agent.vpsserver.common.utils.common.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 时间工具类
 *
 * @author <a href="mailto:ludezheng@hongrz.com"> ludezh </a>
 * @version 1.0.0   2018/10/7,15:43
 * @since 1.0.0     2018/10/7,15:43
 */
@Slf4j
public class DateUtils {

    public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String MINUTE_PATTERN = "yyyy/MM/dd HH:mm";
    public static final String HOUR_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String ALL_PATTERN = "yyyyMMddHHmmss";
    public static final String DATE_PATTERN = "yyyy-MM-dd";
    public static final String MONTH_PATTERN = "yyyy-MM";
    public static final String YEAR_PATTERN = "yyyy";
    public static final String MINUTE_ONLY_PATTERN = "mm";
    public static final String HOUR_ONLY_PATTERN = "HH";
    public static final String YYYY_MM_DD_CN = "yyyy年MM月dd日";
    public static final String YYYY_MM_DD_HH_MM_SS_CN = "yyyy年MM月dd日 HH:mm:ss";

    /**
     * <p>
     * Description: 构造函数
     * </p>
     */
    private DateUtils() {
    }

    /**
     * 获取某个日期到该月月底的距离天数包括今天
     *
     * @param localDate
     * @param isIncludeToday
     * @return java.lang.Integer
     * @author ludezh
     * @date 2019/8/27 14:32
     * @version 1.0.0
     */
    public static Integer awayEndOfMonthDays(Date localDate, Boolean isIncludeToday) {
        if (null == localDate) {
            localDate = new Date();
        }
        Date date = null;
        try {
            // 获取当前时间月份最大的一天
            date = DateUtils.maxDateOfMonth(localDate);
            if (null == isIncludeToday || isIncludeToday) {
                // 比较当前时间 距离 该月月底 相差多少天 包括今天在内
                return DateUtils.dateBetweenIncludeToday(localDate, date);
            } else {
                return DateUtils.dateBetween(localDate, date);
            }
        } catch (ParseException e) {
            log.error("解析日期发生异常:", e.getMessage());
        }
        return null;
    }

    /**
     * 判断某个时间是否在本月中
     *
     * @param [date]
     * @return boolean
     * @author ludezh
     * @date 2019/8/26 23:05
     * @version 1.0.0
     */
    public static boolean dateInLocalMonth(Date date) {
        // 截取年月
        String yM = DateUtils.dateFormat(date, "").substring(7);
        String local = DateUtils.dateFormat(new Date(), "").substring(7);
        if (yM.equals(local)) {
            return true;
        }
        return false;
    }

    /**
     * 当前时间+1年
     *
     * @return
     */
    public static Long nowAfter1Year() {
        return LocalDateTime.now().plusYears(1).toEpochSecond(ZoneOffset.of("+8"));
    }

    /**
     * 获取当前时间
     *
     * @return yyyy-MM-dd HH:mm:ss
     */
    public static String getNowStr() {
        return DateUtils.getNowStr(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN));
    }

    /**
     * 获取当前时间，返回指定格式
     *
     * @param formatter 指定格式
     * @return 当前时间
     */
    public static String getNowStr(DateTimeFormatter formatter) {
        LocalDateTime time = LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault());
        return time.format(formatter);
    }

    /**
     * 时间戳转日期字符串(中文格式)
     *
     * @param date
     * @return
     */
    public static String date2Str(LocalDateTime date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
        return date.format(formatter);
    }

    /**
     * 字符串转换成日期
     *
     * @param str
     * @return date
     */
    public static Date strToDate(String str) {
        SimpleDateFormat format = new SimpleDateFormat(DATE_TIME_PATTERN);
        Date date = null;
        try {
            date = format.parse(str);
        } catch (ParseException e) {
            log.error(e.getMessage());
        }
        return date;
    }

    /**
     * 时间戳转日期字符串(中文格式)
     *
     * @param date
     * @return
     */
    public static String date2StrCNBig(Date date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS_CN);
        Instant instant = date.toInstant();
        LocalDateTime time = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return time.format(formatter);
    }

    /**
     * 时间戳转日期字符串(中文格式)
     *
     * @param date
     * @return
     */
    public static String date2StrCNSmall(Date date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_CN);
        Instant instant = date.toInstant();
        LocalDateTime time = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return time.format(formatter);
    }

    /**
     * 时间戳转日期字符串
     *
     * @param date
     * @return
     */
    public static String date2Str(Date date, String timeFormatter) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(timeFormatter);
        Instant instant = date.toInstant();
        LocalDateTime time = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return time.format(formatter);
    }


    /**
     * 时间戳转日期字符串(中文格式)
     *
     * @param timestamp
     * @return
     */
    public static String long2DateCNBig(Long timestamp) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS_CN);
        Instant instant = Instant.ofEpochSecond(timestamp);
        LocalDateTime time = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return time.format(formatter);
    }

    /**
     * 时间戳转日期字符串(中文格式)
     *
     * @param timestamp
     * @return
     */
    public static String long2DateCNSmall(Long timestamp) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_CN);
        Instant instant = Instant.ofEpochSecond(timestamp);
        LocalDateTime time = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return time.format(formatter);
    }

    /**
     * 时间戳转日期字符串
     *
     * @param timestamp
     * @return
     */
    public static String long2DateStr(Long timestamp, String timeFormatter) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(timeFormatter);
        Instant instant = Instant.ofEpochSecond(timestamp);
        LocalDateTime time = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return time.format(formatter);
    }

    /**
     * 获取timestamp时间戳字符串
     *
     * @return
     */
    public static String getTimestampStr() {
        return String.valueOf(getTimestamp());
    }

    /**
     * 获取timestamp时间戳
     *
     * @return
     */
    public static Long getTimestamp() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 获得某天最大时间 2017-10-15 23:59:59
     *
     * @param date
     * @return
     */
    public static Date getEndOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当天开始时间 如2017-10-15 00:00:00
     *
     * @param date
     * @return
     */
    public static Date getStartOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
        return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当天开始时间 如2017-10-15 00:00:00
     *
     * @param date
     * @return
     */
    public static Date getStartOfHour(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 1、日期相加减天数
     *
     * @param date        如果为Null，则为当前时间
     * @param days        加减天数
     * @param includeTime 是否包括时分秒,true表示包含
     * @return
     * @throws ParseException
     */
    public static Date dateAdd(Date date, int days, boolean includeTime) throws ParseException {
        if (date == null) {
            date = new Date();
        }
        if (!includeTime) {
            SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.DATE_PATTERN);
            date = sdf.parse(sdf.format(date));
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, days);
        return cal.getTime();
    }

    /**
     * 当时、分、秒为00:00:00时，将日期时间格式成只有日期的字符串，
     * 当时、分、秒不为00:00:00时，直接返回
     *
     * @param dateTime Date
     * @return
     * @throws ParseException
     */
    public static String dateTimeToDateStringIfTimeEndZero(Date dateTime) throws ParseException {
        String dateTimeString = DateUtils.dateFormat(dateTime, DateUtils.DATE_TIME_PATTERN);
        if (dateTimeString.endsWith("00:00:00")) {
            return dateTimeString.substring(0, 10);
        } else {
            return dateTimeString;
        }
    }

    /**
     * 时间格式化成字符串
     *
     * @param date    Date
     * @param pattern StrUtils.DATE_TIME_PATTERN || StrUtils.DATE_PATTERN， 如果为空，则为yyyy-MM-dd
     * @return
     */
    public static String dateFormat(Date date, String pattern) {
        if (StringUtils.isBlank(pattern)) {
            pattern = DateUtils.DATE_PATTERN;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * 字符串解析成时间对象
     *
     * @param dateTimeString String
     * @param pattern        StrUtils.DATE_TIME_PATTERN || StrUtils.DATE_PATTERN，如果为空，则为yyyy-MM-dd
     * @return
     * @throws ParseException
     */
    public static Date dateParse(String dateTimeString, String pattern) throws ParseException {
        if (StringUtils.isBlank(pattern)) {
            pattern = DateUtils.DATE_PATTERN;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.parse(dateTimeString);
    }

    /**
     * 将日期时间格式成日期对象，和dateParse互用
     *
     * @param dateTime Date
     * @return Date
     * @throws ParseException
     */
    public static Date dateTimeToDate(Date dateTime) throws ParseException {
        Calendar cal = Calendar.getInstance();
        cal.setTime(dateTime);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 时间加减小时
     *
     * @param startDate 要处理的时间，Null则为当前时间
     * @param hours     加减的小时
     * @return Date
     */
    public static Date dateAddHours(Date startDate, int hours) {
        if (startDate == null) {
            startDate = new Date();
        }
        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        c.add(Calendar.HOUR, hours);
        return c.getTime();
    }

    /**
     * 时间加减分钟
     *
     * @param startDate 要处理的时间，Null则为当前时间
     * @param minutes   加减的分钟
     * @return
     */
    public static Date dateAddMinutes(Date startDate, int minutes) {
        if (startDate == null) {
            startDate = new Date();
        }
        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        c.add(Calendar.MINUTE, minutes);
        return c.getTime();
    }

    /**
     * 时间加减秒数
     *
     * @param startDate 要处理的时间，Null则为当前时间
     * @param seconds   加减的秒数
     * @return
     */
    public static Date dateAddSeconds(Date startDate, int seconds) {
        if (startDate == null) {
            startDate = new Date();
        }
        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        c.add(Calendar.SECOND, seconds);
        return c.getTime();
    }

    /**
     * 时间加减天数
     *
     * @param startDate 要处理的时间，Null则为当前时间
     * @param days      加减的天数
     * @return Date
     */
    public static Date dateAddDays(Date startDate, int days) {
        if (startDate == null) {
            startDate = new Date();
        }
        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        c.add(Calendar.DATE, days);
        return c.getTime();
    }

    /**
     * 时间加减月数
     *
     * @param startDate 要处理的时间，Null则为当前时间
     * @param months    加减的月数
     * @return Date
     */
    public static Date dateAddMonths(Date startDate, int months) {
        if (startDate == null) {
            startDate = new Date();
        }
        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        c.add(Calendar.MONTH, months);
        return c.getTime();
    }

    /**
     * 时间加减年数
     *
     * @param startDate 要处理的时间，Null则为当前时间
     * @param years     加减的年数
     * @return Date
     */
    public static Date dateAddYears(Date startDate, int years) {
        if (startDate == null) {
            startDate = new Date();
        }
        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        c.add(Calendar.YEAR, years);
        return c.getTime();
    }

    /**
     * 时间比较（如果myDate>compareDate返回1，<返回-1，相等返回0）
     *
     * @param myDate      时间
     * @param compareDate 要比较的时间
     * @return int
     */
    public static int dateCompare(Date myDate, Date compareDate) {
        Calendar myCal = Calendar.getInstance();
        Calendar compareCal = Calendar.getInstance();
        myCal.setTime(myDate);
        compareCal.setTime(compareDate);
        return myCal.compareTo(compareCal);
    }

    /**
     * 获取两个时间中最小的一个时间
     *
     * @param date
     * @param compareDate
     * @return
     */
    public static Date dateMin(Date date, Date compareDate) {
        if (date == null) {
            return compareDate;
        }
        if (compareDate == null) {
            return date;
        }
        if (1 == dateCompare(date, compareDate)) {
            return compareDate;
        } else if (-1 == dateCompare(date, compareDate)) {
            return date;
        }
        return date;
    }

    /**
     * 获取两个时间中最大的一个时间
     *
     * @param date
     * @param compareDate
     * @return
     */
    public static Date dateMax(Date date, Date compareDate) {
        if (date == null) {
            return compareDate;
        }
        if (compareDate == null) {
            return date;
        }
        if (1 == dateCompare(date, compareDate)) {
            return date;
        } else if (-1 == dateCompare(date, compareDate)) {
            return compareDate;
        }
        return date;
    }

    /**
     * 获取两个时间相差的钟头数
     *
     * @param startDate
     * @param endDate
     * @return
     * @throws ParseException
     */
    public static int timeBetween(Date startDate, Date endDate) throws ParseException {
        Date dateStart = dateParse(dateFormat(startDate, HOUR_PATTERN), HOUR_PATTERN);
        Date dateEnd = dateParse(dateFormat(endDate, HOUR_PATTERN), HOUR_PATTERN);
        return (int) ((dateEnd.getTime() - dateStart.getTime()) / 1000 / 60 / 60);
    }

    /**
     * 获取两个日期（不含时分秒）相差的天数，不包含今天
     *
     * @param startDate
     * @param endDate
     * @return
     * @throws ParseException
     */
    public static int dateBetween(Date startDate, Date endDate) throws ParseException {
        Date dateStart = dateParse(dateFormat(startDate, DATE_PATTERN), DATE_PATTERN);
        Date dateEnd = dateParse(dateFormat(endDate, DATE_PATTERN), DATE_PATTERN);
        return (int) ((dateEnd.getTime() - dateStart.getTime()) / 1000 / 60 / 60 / 24);
    }

    /**
     * 获取两个日期（不含时分秒）相差的天数，包含今天
     *
     * @param startDate
     * @param endDate
     * @return
     * @throws ParseException
     */
    public static int dateBetweenIncludeToday(Date startDate, Date endDate) throws ParseException {
        return dateBetween(startDate, endDate) + 1;
    }

    /**
     * 获取日期时间的年份，如2017-02-13，返回2017
     *
     * @param date
     * @return
     */
    public static int getYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.YEAR);
    }

    /**
     * 获取日期时间的月份，如2017年2月13日，返回2
     *
     * @param date
     * @return
     */
    public static int getMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取日期时间的第几天（即返回日期的dd），如2017-02-13，返回13
     *
     * @param date
     * @return
     */
    public static int getDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DATE);
    }

    /**
     * 获取日期时间当月的总天数，如2017-02-13，返回28
     *
     * @param date
     * @return
     */
    public static int getDaysOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getActualMaximum(Calendar.DATE);
    }

    /**
     * 获取日期时间当年的总天数，如2017-02-13，返回2017年的总天数
     *
     * @param date
     * @return
     */
    public static int getDaysOfYear(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getActualMaximum(Calendar.DAY_OF_YEAR);
    }

    /**
     * 获取日期时间是本周的第几天，例如周二的日期，返回2
     *
     * @param date
     * @return
     */
    public static int getDayOfWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 获取秒为单位的时间戳
     *
     * @param date
     * @return
     */
    public static Long getTimeStamp(Date date) {
        return date.getTime() / 1000;
    }

    /**
     * 根据时间获取当月最大的日期
     * <li>2017-02-13，返回2017-02-28</li>
     * <li>2016-02-13，返回2016-02-29</li>
     * <li>2016-01-11，返回2016-01-31</li>
     *
     * @param date Date
     * @return
     * @throws Exception
     */
    public static Date maxDateOfMonth(Date date) throws ParseException {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int value = cal.getActualMaximum(Calendar.DATE);
        return dateParse(dateFormat(date, MONTH_PATTERN) + "-" + value, null);
    }

    /**
     * 根据时间获取当月最小的日期，也就是返回当月的1号日期对象
     *
     * @param date Date
     * @return
     * @throws Exception
     */
    public static Date minDateOfMonth(Date date) throws Exception {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int value = cal.getActualMinimum(Calendar.DATE);
        return dateParse(dateFormat(date, MONTH_PATTERN) + "-" + value, null);
    }

    /**
     * 根据时间获取当月最小的时间戳，也就是返回yyyy-MM-01 00:00:00的时间戳
     *
     * @param dateStr 时间字符串
     * @param format  时间格式
     * @return
     */
    public static Long getMinDateTimeOfMonth(String dateStr, String format) {
        LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(format));
        return date.withDayOfMonth(1).atStartOfDay().toEpochSecond(ZoneOffset.ofHours(8));
    }

    /**
     * 根据时间获取当月最小的时间戳，也就是返回yyyy-MM-01 00:00:00的时间戳
     *
     * @param date
     * @return
     */
    public static Long getMinDateTimeOfMonth(Date date) {
        LocalDate localDate = LocalDateTime.ofEpochSecond(date.getTime() / 1000, 0, ZoneOffset.ofHours(8)).toLocalDate();
        return localDate.withDayOfMonth(1).atStartOfDay().toEpochSecond(ZoneOffset.ofHours(8));
    }

    /**
     * 根据时间获取当月最大的时间戳，也就是返回yyyy-MM-max 23:59:59的时间戳
     *
     * @param dateStr 时间字符串
     * @param format  时间格式
     * @return
     */
    public static Long getMaxDateTimeOfMonth(String dateStr, String format) {
        LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(format));
        return date.plusMonths(1).withDayOfMonth(1).atStartOfDay().toEpochSecond(ZoneOffset.ofHours(8)) - 1;
    }

    /**
     * 根据时间获取当月最大的时间戳，也就是返回yyyy-MM-max 23:59:59的时间戳
     *
     * @param date
     * @return
     */
    public static Long getMaxDateTimeOfMonth(Date date) {
        LocalDate localDate = LocalDateTime.ofEpochSecond(date.getTime() / 1000, 0, ZoneOffset.ofHours(8)).toLocalDate();
        return localDate.plusMonths(1).withDayOfMonth(1).atStartOfDay().toEpochSecond(ZoneOffset.ofHours(8)) - 1;
    }

    /**
     * 日期(时间)转化为字符串.
     *
     * @param formater 日期或时间的格式.
     * @param aDate    java.utils.Date类的实例.
     * @return 日期转化后的字符串.
     */
    public static String dateToString(String formater, Date aDate) {
        if (formater == null || "".equals(formater)) {
            return null;
        }
        if (aDate == null) {
            return null;
        }
        return (new SimpleDateFormat(formater)).format(aDate);
    }

    /**
     * 当前日期(时间)转化为字符串.
     *
     * @param formater 日期或时间的格式.
     * @return 日期转化后的字符串.
     */
    public static String dateToString(String formater) {
        return dateToString(formater, new Date());
    }


    /**
     * 获取所有的时区编号. <br>
     * 排序规则:按照ASCII字符的正序进行排序. <br>
     * 排序时候忽略字符大小写.
     *
     * @return 所有的时区编号(时区编号已经按照字符[忽略大小写]排序).
     */
    public static List<String> fecthAllTimeZoneIds() {
        List<String> v = new ArrayList<>();
        String[] ids = TimeZone.getAvailableIDs();
        Arrays.stream(ids).forEach(id -> { //NOSONAR
            v.add(id);
        });
        Collections.sort(v, String.CASE_INSENSITIVE_ORDER);
        return v;
    }

    /**
     * 将日期时间字符串根据转换为指定时区的日期时间.
     *
     * @param srcFormater   待转化的日期时间的格式.
     * @param srcDateTime   待转化的日期时间.
     * @param dstFormater   目标的日期时间的格式.
     * @param dstTimeZoneId 目标的时区编号.
     * @return 转化后的日期时间.
     * @throws ParseException 异常
     */
    public static String stringToTimezone(String srcFormater, String srcDateTime, String dstFormater, String dstTimeZoneId) throws ParseException { //NOSONAR
        if (srcFormater == null || "".equals(srcFormater)) {
            return null;
        }
        if (srcDateTime == null || "".equals(srcDateTime)) {
            return null;
        }
        if (dstFormater == null || "".equals(dstFormater)) {
            return null;
        }
        if (dstTimeZoneId == null || "".equals(dstTimeZoneId)) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(srcFormater);
        int diffTime = getDiffTimeZoneRawOffset(dstTimeZoneId);
        Date d = sdf.parse(srcDateTime);
        long nowTime = d.getTime();
        long newNowTime = nowTime - diffTime;
        d = new Date(newNowTime);
        return dateToString(dstFormater, d);
    }

    /**
     * 获取系统当前默认时区与UTC的时间差.(单位:毫秒)
     *
     * @return 系统当前默认时区与UTC的时间差.(单 = 毫秒)
     */
    public static int getDefaultTimeZoneRawOffset() {
        return TimeZone.getDefault().getRawOffset();
    }

    /**
     * <p>
     * Description: 返回UTC与指定时区的时间差
     * </p>
     *
     * @param timeZoneId 时区ID
     * @return 时差
     */
    public static String getUtcTimeZoneRawOffset(String timeZoneId) {
        return new SimpleDateFormat("HH:mm").format(getTimeZoneRawOffset(timeZoneId));
    }

    /**
     * 获取指定时区与UTC的时间差.(单位:毫秒)
     *
     * @param timeZoneId 时区Id
     * @return 指定时区与UTC的时间差.(单位 = 毫秒)
     */
    public static int getTimeZoneRawOffset(String timeZoneId) {
        return TimeZone.getTimeZone(timeZoneId).getRawOffset();
    }

    /**
     * 获取系统当前默认时区与指定时区的时间差.(单位:毫秒)
     *
     * @param timeZoneId 时区Id
     * @return 系统当前默认时区与指定时区的时间差.(单位 = 毫秒)
     */
    private static int getDiffTimeZoneRawOffset(String timeZoneId) {
        return TimeZone.getDefault().getRawOffset() - TimeZone.getTimeZone(timeZoneId).getRawOffset();
    }

    /**
     * 将日期时间字符串根据转换为指定时区的日期时间.
     *
     * @param srcDateTime   待转化的日期时间.
     * @param dstTimeZoneId 目标的时区编号.
     * @return 转化后的日期时间.
     * @throws ParseException 异常
     */
    public static String stringToTimezoneDefault(String srcDateTime, String dstTimeZoneId) throws ParseException {
        return stringToTimezone("yyyy-MM-dd HH:mm:ss", srcDateTime, "yyyy-MM-dd HH:mm:ss", dstTimeZoneId);
    }

    /**
     * 字符串转换成日期
     *
     * @param str
     * @return date
     */
    public static Date strToDate(String str, String patters) {
        SimpleDateFormat format = new SimpleDateFormat(patters);
        Date date = null;
        try {
            date = format.parse(str);
        } catch (ParseException e) {
            log.error(e.getMessage());
        }
        return date;
    }

    /**
     * 时间戳转为时间
     *
     * @param s
     * @return
     */
    public static String stampToDate(Long s) {
        String res;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(s);
        res = simpleDateFormat.format(date);
        return res;
    }

    /**
     * 用于Excel时间格式是43188.468333这种格式时的日期处理(获取到天)
     *
     * @param days
     * @return
     */
    public static Date getDay(int days) {
        Calendar c = Calendar.getInstance();
        c.set(1900, 0, 1);
        c.add(Calendar.DATE, days - 2);
        return c.getTime();
    }

    /**
     * 用于Excel时间格式是43188.468333这种格式时的时间处理(获取时间)
     *
     * @param date
     * @param ditNumber
     * @return
     */
    public static Date getTime(Date date, double ditNumber) {
        Calendar c = Calendar.getInstance();
        int mills = (int) (Math.round(ditNumber * 24 * 3600));
        int hour = mills / 3600;
        int minute = (mills - hour * 3600) / 60;
        int second = mills - hour * 3600 - minute * 60;
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, hour);
        c.set(Calendar.MINUTE, minute);
        c.set(Calendar.SECOND, second);
        return c.getTime();
    }

    /**
     * 用于Excel时间格式是43188.468333这种格式时的时间处理(获取时间和日期)
     *
     * @param timeStamp
     * @return 返回完整时间
     */
    public static Date getDate(String timeStamp) {
        int index = timeStamp.lastIndexOf(".");
        int length = timeStamp.length();
        int days = Integer.parseInt(timeStamp.substring(0, index));
        double ditNumber = Double.parseDouble("0" + timeStamp.substring(index, length));
        Date date = DateUtils.getDay(days);
        return DateUtils.getTime(date, ditNumber);
    }

    /**
     * 返回特定的日期格式
     * 1.所选时间为本年度，则不显示年份，否则显示年份
     * 2.所选时间不需要展示日时，当月显示本月，否则显示月份
     * 3.所选时间需要显示日时，按yyyy年MM月dd日显示，并且前置0不需要
     *
     * @param date    需要转换的日期
     * @param showDay 是否展示日
     * @return
     */
    public static String dateFormatCN(Date date, boolean showDay) {
        Date now = new Date();
        StringBuilder sb = new StringBuilder();
        if (getYear(date) != getYear(now)) {
            sb.append(getYear(date));
            sb.append("年");
        } else {
            // 同年，同月，且不显示日期
            if (getMonth(date) == getMonth(now) && !showDay) {
                return "本月";
            }
        }
        sb.append(getMonth(date));
        sb.append("月");
        if (showDay) {
            sb.append(getDate(date));
            sb.append("日");
        }
        return sb.toString();
    }
}
